package sistemadeecuacioneslineales;
import sistemadeecuacioneslineales.excepciones.ExcepcionSEL;

public class MatrizMath {
	
	private int fila, col;
	private float [][] mat;
	

	
    //CONSTRUCTOR PARAMETRIZADO POR DEFECTO
	public MatrizMath(int f, int c)
	{
	 	fila = f;
		col = c;
		
		mat = new float [fila] [col];		
		
	}

	public MatrizMath()
	{
		this(0,0);
	}
	
	 			  
	  	  
	public int getFila() {
		return fila;
	}

	public void setFila(int fila) {
		this.fila = fila;
	}

	public int getCol() {
		return col;
	}

	public void setCol(int col) {
		this.col = col;
	}

	public float[][] getMat() {
		return mat;
	}

	public void setMat(float[][] mat) {
		this.mat = mat;
	}

	public MatrizMath sumar (MatrizMath obj) throws ExcepcionSEL
	{
	    if(fila == obj.fila && col == obj.col)
	     {
		  		MatrizMath aux= new MatrizMath(fila, col);
		  		
		  		for(int i=0; i<fila; i++)
		  		 for(int j=0; j<col; j++)
		  		   aux.mat[i][j] = mat[i][j] + obj.mat[i][j];
		  	   
				 return aux;	   
	     } 		   
	    else
	     { 
	    	throw new ExcepcionSEL("Las matrices no se pueden sumar");
		  
	     }  
	    
	}    


	//OPERATOR - (RESTA DE MATRICES)
	public MatrizMath restar (MatrizMath obj) throws ExcepcionSEL
	{
	    if(fila == obj.fila && col == obj.col)
	     {
		  		MatrizMath aux= new MatrizMath(fila, col);
		  		
		  		for(int i=0; i<fila; i++)
		  		 for(int j=0; j<col; j++)
		  		   aux.mat[i][j] = mat[i][j] - obj.mat[i][j];
		  	   
				 return aux;	   
	     } 		   
	    else
	     { 
	    	throw new ExcepcionSEL("Las matrices no se pueden restar");
			   
	     }  
	    
	}  


	//OPERATOR =
	public void clone (MatrizMath obj)
	{
	 	if(fila != obj.fila || col != obj.col)
	 	{		 	  	
			fila = obj.fila;
		    col = obj.col;     
			 	 	 	   
	    }
		
		for(int i=0; i< fila; i++)
			for(int j=0; j<col; j++)
				mat[i][j] = obj.mat[i][j];    
		  	
	}		  	  


	//OPERATOR * (MATRIZ X UN NUMERO)
	public MatrizMath multiplicar(float num)
	{
	 	MatrizMath aux= new MatrizMath(fila, col);	
		
		for(int i=0; i<fila; i++)
		  for(int j=0; j<col; j++)
		    aux.mat[i][j] = mat[i][j] *num;
			
		return aux;	   
	}


	//OPERATOR * (MATRIZ * MATRIZ)
	public MatrizMath multiplicar ( MatrizMath obj) throws ExcepcionSEL
	{
	    if(col != obj.fila)
	     {
	    	throw new ExcepcionSEL( "No se puede multiplicat");
	 	   
	     }
		 
		MatrizMath aux= new MatrizMath(fila, obj.col);
		
		for(int c=0; c < obj.col; c++)
		  for(int f=0; f < fila; f++)
		    for(int k=0; k < obj.fila; k++)
		      aux.mat[f][c] = mat[f][k] * obj.mat[k][c];
		 
		return aux;
	}	      


	//OPERATOR ==
	public boolean equals (MatrizMath obj)
	{
	 	if(fila == obj.fila && col == obj.col)
		 {
		   for(int i=0; i<fila; i++)
		     for(int j=0; j<col; j++)	 
			   if(mat[i][j] != obj.mat[i][j])
			      return false; 
	     }
		else
		  return false;
	 	
		return true;

	}	   	      



	//MATRIZ * VECTOR
	public VectorMath multiplicar (VectorMath v) throws ExcepcionSEL
	{
	     if (v.tam != col)
	     {
	    	 throw new ExcepcionSEL("No se puede multiplicar");
	        
	     }
	     VectorMath aux= new VectorMath(fila);	    
	     	    
	     for (int i=0; i<fila; i++)
		    for (int j=0; j<col; j++)
	            aux.setValue(i, aux.getValue(i) + (mat[i][j] * v.getValue(j)));
	            
	     return aux;
	}
 		  
	//DETERMINANTE
	public float determinante()
	{
	     if(fila != col)
	      return 0;
	   
	     if(fila == 1)
	      return (mat [0][0]);
	 	
	     float valor1=0;
	     float valor2=0;
	     
	     if(fila == 2)
	     {  
	       valor1= mat[0][0]* mat[1][1];
	       valor2= mat[0][1]* mat[1][0];
	       return (valor1-valor2);
	     }
	     
	     //Calcula el determinante para una matriz de 3X3 o mayor
	     for (int c=0; c < fila; c++)
	        valor1 += mat[0][c] *  this.adjunto(0,c);
	 
	     return valor1;
	}

	//ADJUNTO (se usa en otras funciones, no es matriz adjunta)	
	private float adjunto (int I,int J)
	{
	     float det;
	     MatrizMath aux = new MatrizMath(fila-1, col-1);
	     int k=0, w, factor=1;

	     //tacho fila y col del adjunto, y cargo los datos en la matriz nueva
	     for (int i=0; i<fila; i++)
	     {
		   if (i!=I)
		   {
			  w=0;
			  for (int j=0;j<col;j++)
			  {
			     if (j!=J)
				 {
					 aux.mat[k][w]=mat[i][j];
					 w++;
				 }
			  }
		      k++;
		  }
	     }//for
	 
	    det = aux.determinante();
	 
	    if (I+J==0)
		  factor=1;
	    else
		  for (int i=1; i<=I+J; i++)
			 factor *= -1;
			
	    return (det*factor);
	}
//TRASPUESTA
	public MatrizMath traspuesta()
	{
	    MatrizMath tras= new MatrizMath(fila, col);
	    
	    for(int i=0; i<fila; i++)
	      for(int j=0; j<col; j++)
	         tras.mat[i][j] = this.mat[j][i];
	         
	     return tras;    
	    
	}


	//ADJUNTA
	public MatrizMath  adjunta()
	{
	   MatrizMath adj= new MatrizMath(fila,col);
	   
	   if (col == 1)
	 	return this;
	 
	   if (col == 2)
	   {
	     adj.mat[0][0]= mat[1][1];
	     adj.mat[0][1]=(mat[1][0])*(-1);
	     adj.mat[1][0]=(mat[0][1])*(-1);
	     adj.mat[1][1]= mat[0][0];
	   }
	   else
	   {
	   	 for(int i=0; i<fila; i++)
	      for(int j=0; j<col; j++)
	         adj.mat[i][j] = this.adjunto(i, j);
	   }       
	   
	    return adj;      
	}

	//INVERSA
	
	public MatrizMath inversa()
	{
	    MatrizMath inversa= new MatrizMath(fila, col);
	    
	    
	    if(col == 1 && this.determinante() != 0)
	      {
	  	   inversa.mat[0][0] = (1/ (this.mat[0][0]));
	       return inversa;
	      } 
	      
	    MatrizMath traspuesta= new MatrizMath(fila, col);
	    MatrizMath adjunta= new MatrizMath(fila, col);
	        
	    float det;
	    
	    det = this.determinante();
	    adjunta = this.adjunta();
	    traspuesta = adjunta.traspuesta();
	    inversa = traspuesta.multiplicar(1/det);
	    
	    return inversa;  
	}



	//SOBRECARGA []
	
	float getValue (int fil, int col)
	{
	  	if(fil < 0 && fil > fila )
	  	 System.out.println("No existe la fila");
	  	if(fil < 0 && fil > fila )
	  	{  	
	  		System.out.println("No existe la fila");	  		
	  	}
	  	if(col < 0 && col > this.col )
		  	 System.out.println("No existe la columna");
		  	 
	  	return mat[fil][col];
	}
	
	void setValue (int fil, int col,float dato){
		if(fil < 0 && fil > fila )
		  	 System.out.println("No existe la fila");
		  	if(fil < 0 && fil > fila )
		  	{  	
		  		System.out.println("No existe la fila");	  		
		  	}
		  	if(col < 0 && col > this.col )
			  	 System.out.println("No existe la columna");
		  	mat[fil][col] = dato;	
	}



	//FUNCION TEST
	boolean test()
	{
	 	 
	     try {
			for (int i=0;i<50;i++)
			 {
			     MatrizMath m1=new MatrizMath();
			     MatrizMath m2 = new MatrizMath(3,3);
			     MatrizMath m3 = new MatrizMath(3,3);
			     MatrizMath m4 = new MatrizMath(5,5);
			     float a,b;
			    
			     m3.clone(m2);
			     
			     if (! m2.equals(m3)) 
			        return false;
			     
			     if (m2.equals(m4))
			        return false;
			        
			     if (m1.equals(m4))
			        return false;
			        
			     m1=m2.sumar(m3);
			     m4=m2.sumar(m3);
			     
			     if (! m1.equals(m4))
			        return false;
			        
			     if (! m2.equals(m3))
			        return false;
			        
			     if (m1.equals(m2))
			        return false;
			        
			     m1 = m2.multiplicar(2);
			     
			     if (! m1.equals(m4))
			        return false;
			     
			     if (m2.equals(m3))
			        return false;
			        
			     m4 = m1.restar(m2);
			     
			     if (m1.equals(m4))
			        return false;
			     
			     if (! m4.equals(m2))
			        return false;
			        
			     a=m4.getValue(2,2);
			     b=m2.getValue(2,2);
			     
			     if (a != b)
			        return false;
			        
			     m1=m3.multiplicar(m4);
			     m2=m3.multiplicar(m4);
			     
			     if (! m1.equals(m2))
			        return false;
			        
			     if (m1.equals(m3))
			        return false;
			        
			     if (! m3.equals(m4))
			        return false;
			 
			 }
			 return true;
		} catch (ExcepcionSEL e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	   
	}	
		


	  
	  
		  	
}
